bitkeeper revision 1.1159.65.1 (4133a979YYvSU8Cjqbo3qyIcdTx6pw)
authorkaf24@freefall.cl.cam.ac.uk <kaf24@freefall.cl.cam.ac.uk>
Mon, 30 Aug 2004 22:26:01 +0000 (22:26 +0000)
committerkaf24@freefall.cl.cam.ac.uk <kaf24@freefall.cl.cam.ac.uk>
Mon, 30 Aug 2004 22:26:01 +0000 (22:26 +0000)
Grant-issuing side of Linux grant-table code. The grant-receiving side
is still to be implemented.

linux-2.4.27-xen-sparse/include/asm-xen/fixmap.h
linux-2.6.8.1-xen-sparse/arch/xen/kernel/gnttab.c
linux-2.6.8.1-xen-sparse/include/asm-xen/asm-i386/fixmap.h
linux-2.6.8.1-xen-sparse/include/asm-xen/hypervisor.h

index 338bd4ba2cf05ce3bf36e25347875fad5391b74d..bc6e2c2004ea945ea578efdb9984449570ac3130 100644 (file)
@@ -52,7 +52,7 @@ enum fixed_addresses {
        FIX_NETRING2_BASE,
        FIX_NETRING3_BASE,
         FIX_SHARED_INFO,
-
+       FIX_GNTTAB,
 #ifdef CONFIG_VGA_CONSOLE
 #define NR_FIX_BTMAPS   32  /* 128KB For the Dom0 VGA Console A0000-C0000 */
 #else
index 008dfa9779d783f8891b4f63528e3166b01df167..c76df4b1e460299159225bbcc1b0dcb5fb063267 100644 (file)
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
 #include <asm-xen/gnttab.h>
 
+#ifndef set_fixmap_ma
+#define set_fixmap_ma set_fixmap
+#endif
+
+#if 1
+#define ASSERT(_p) \
+    if ( !(_p) ) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \
+    #_p , __LINE__, __FILE__); *(int*)0=0; }
+#else
+#define ASSERT(_p) ((void)0)
+#endif
+
 EXPORT_SYMBOL(gnttab_grant_foreign_access);
 EXPORT_SYMBOL(gnttab_end_foreign_access);
 EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
 EXPORT_SYMBOL(gnttab_end_foreign_transfer);
 
+struct gntent_auxinfo {
+    u16         write_pin, read_pin; /* reference counts */
+    u16         inuse;
+    grant_ref_t next;                /* hash chain       */
+};
+
+#define NR_GRANT_REFS 512
+
+static struct gntent_auxinfo auxtab[NR_GRANT_REFS];
+static grant_ref_t gnttab_free_head;
+static spinlock_t gnttab_lock;
+
+#define HASH_INVALID (0xFFFFU)
+#define GNTTAB_HASH_SZ 512
+#define GNTTAB_HASH(_f) ((_f) & (GNTTAB_HASH_SZ-1))
+static grant_ref_t gnttab_hash[GNTTAB_HASH_SZ];
+
+static grant_entry_t *shared;
+
+/*
+ * Lock-free grant-entry allocator
+ */
+
+static inline grant_ref_t
+get_free_entry(
+    void)
+{
+    grant_ref_t fh, nfh = gnttab_free_head;
+    do { fh = nfh; }
+    while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh,
+                                    auxtab[fh].next)) != fh) );
+    return fh;
+}
+
+static inline void
+put_free_entry(
+    grant_ref_t ref)
+{
+    grant_ref_t fh, nfh = gnttab_free_head;
+    do { auxtab[ref].next = fh = nfh; wmb(); }
+    while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh, ref)) != fh) );
+}
+
+/*
+ * Public interface functions
+ */
+
 grant_ref_t
 gnttab_grant_foreign_access(
     domid_t domid, unsigned long frame, int readonly)
 {
+    unsigned long flags;
+    grant_ref_t   ref;
+
+    spin_lock_irqsave(&gnttab_lock, flags);
+
+    for ( ref  = gnttab_hash[GNTTAB_HASH(frame)];
+          ref != HASH_INVALID;
+          ref  = auxtab[ref].next )
+    {
+        if ( auxtab[ref].inuse && (shared[ref].frame == frame) )
+        {
+            if ( readonly )
+                auxtab[ref].read_pin++;
+            else if ( auxtab[ref].write_pin++ == 0 )
+                clear_bit(_GTF_readonly, (unsigned long *)&shared[ref].flags);
+            goto done;
+        }
+    }
+
+    ref = get_free_entry();
+    auxtab[ref].inuse     = 1;
+    auxtab[ref].read_pin  = !!readonly;
+    auxtab[ref].write_pin =  !readonly;
+    auxtab[ref].next = gnttab_hash[GNTTAB_HASH(frame)];
+    gnttab_hash[GNTTAB_HASH(frame)] = ref;
+
+    shared[ref].frame = frame;
+    shared[ref].domid = domid;
+    wmb();
+    shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
+
+ done:
+    spin_unlock_irqrestore(&gnttab_lock, flags);
     return 0;
 }
 
@@ -29,18 +124,111 @@ void
 gnttab_end_foreign_access(
     grant_ref_t ref, int readonly)
 {
+    unsigned long flags, frame = shared[ref].frame;
+    grant_ref_t  *pref;
+    u16           sflags, nsflags;
+
+    spin_lock_irqsave(&gnttab_lock, flags);
+
+    if ( readonly )
+    {
+        if ( (auxtab[ref].read_pin-- == 0) && (auxtab[ref].write_pin == 0) )
+            goto delete;
+    }
+    else if ( auxtab[ref].write_pin-- == 0 )
+    {
+        if ( auxtab[ref].read_pin == 0 )
+            goto delete;
+        nsflags = shared[ref].flags;
+        do {
+            if ( (sflags = nsflags) & GTF_writing )
+                printk(KERN_ALERT "WARNING: g.e. still in use for writing!\n");
+        }
+        while ( (nsflags = cmpxchg(&shared[ref].flags, sflags, 
+                                   sflags | GTF_readonly)) != sflags );
+    }
+
+    goto out;
+
+ delete:
+    nsflags = shared[ref].flags;
+    do {
+        if ( (sflags = nsflags) & (GTF_reading|GTF_writing) )
+            printk(KERN_ALERT "WARNING: g.e. still in use!\n");
+    }
+    while ( (nsflags = cmpxchg(&shared[ref].flags, sflags, 0)) != sflags );
+
+    pref = &gnttab_hash[GNTTAB_HASH(frame)];
+    while ( *pref != ref )
+        pref = &auxtab[*pref].next;
+    *pref = auxtab[ref].next;
+
+    auxtab[ref].inuse = 0;
+    put_free_entry(ref);
+
+ out:
+    spin_unlock_irqrestore(&gnttab_lock, flags);
 }
 
 grant_ref_t
 gnttab_grant_foreign_transfer(
     domid_t domid)
 {
-    return 0;
+    grant_ref_t ref = get_free_entry();
+
+    shared[ref].frame = 0;
+    shared[ref].domid = domid;
+    wmb();
+    shared[ref].flags = GTF_accept_transfer;
+
+    return ref;
 }
 
 unsigned long
 gnttab_end_foreign_transfer(
     grant_ref_t ref)
 {
-    return 0;
+    unsigned long frame = 0;
+    u16           flags;
+
+    flags = shared[ref].flags;
+    ASSERT(flags == (GTF_accept_transfer | GTF_transfer_committed));
+
+    /*
+     * If a transfer is committed then wait for the frame address to appear.
+     * Otherwise invalidate the grant entry against future use.
+     */
+    if ( likely(flags != GTF_accept_transfer) ||
+         (cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) )
+        while ( unlikely((frame = shared[ref].frame) == 0) )
+            cpu_relax();
+
+    put_free_entry(ref);
+
+    return frame;
+}
+
+void __init gnttab_init(void)
+{
+    int               i;
+    gnttab_op_t       gntop;
+    unsigned long     frame;
+
+    spin_lock_init(&gnttab_lock);
+
+    for ( i = 0; i < GNTTAB_HASH_SZ; i++ )
+    {
+        gnttab_hash[i] = HASH_INVALID;
+        auxtab[i].next = i+1;
+    }
+
+    gntop.cmd = GNTTABOP_setup_table;
+    gntop.u.setup_table.dom        = DOMID_SELF;
+    gntop.u.setup_table.nr_frames  = 1;
+    gntop.u.setup_table.frame_list = &frame;
+    if ( HYPERVISOR_grant_table_op(&gntop) != 0 )
+        BUG();
+
+    set_fixmap_ma(FIX_GNTTAB, frame << PAGE_SHIFT);
+    shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB);
 }
index 0bfb839f2028dbb28e01c2d1cb1fd0fa857f3928..89b3ba65329c9f7136456229310e5c4b3fea3f8a 100644 (file)
@@ -75,6 +75,7 @@ enum fixed_addresses {
        FIX_PCIE_MCFG,
 #endif
        FIX_SHARED_INFO,
+       FIX_GNTTAB,
 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
 #define NR_FIX_ISAMAPS 256
        FIX_ISAMAP_END,
index 4198263d14e9041eb9e25d0e8cc267b933e3c93b..4d7ddc55a7f03863c30f0c44b5b7f6173e96edcb 100644 (file)
@@ -466,6 +466,17 @@ static inline int HYPERVISOR_physdev_op(void *physdev_op)
     return ret;
 }
 
+static inline int HYPERVISOR_grant_table_op(void *gnttab_op)
+{
+    int ret;
+    __asm__ __volatile__ (
+        TRAP_INSTR
+        : "=a" (ret) : "0" (__HYPERVISOR_grant_table_op),
+        "b" (gnttab_op) : "memory" );
+
+    return ret;
+}
+
 static inline int HYPERVISOR_update_va_mapping_otherdomain(
     unsigned long page_nr, pte_t new_val, unsigned long flags, domid_t domid)
 {